package cc.iotkit.openapi.controller;

import cc.iotkit.common.api.PageRequest;
import cc.iotkit.common.api.Paging;
import cc.iotkit.common.api.Request;
import cc.iotkit.common.thing.ThingModelMessage;
import cc.iotkit.data.manager.IDeviceInfoData;
import cc.iotkit.manager.dto.bo.device.DeviceLogQueryBo;
import cc.iotkit.manager.dto.bo.device.DeviceQueryBo;
import cc.iotkit.manager.dto.vo.deviceinfo.DeviceInfoMiniVo;
import cc.iotkit.manager.dto.vo.deviceinfo.DeviceInfoVo;
import cc.iotkit.manager.dto.vo.record.DoorAccessRecordVo;
import cc.iotkit.manager.service.AlertService;
import cc.iotkit.manager.service.DoorAccessRecordService;
import cc.iotkit.manager.service.IDeviceManagerService;
import cc.iotkit.model.InvokeResult;
import cc.iotkit.model.alert.AlertRecord;
import cc.iotkit.model.device.DeviceInfo;
import cc.iotkit.model.device.message.DevicePropertyCache;
import cc.iotkit.model.report.DoorAccessRecord;
import cc.iotkit.openapi.dto.bo.device.OpenapiDeviceBo;
import cc.iotkit.openapi.dto.bo.device.OpenapiDevicePublicBo;
import cc.iotkit.openapi.dto.bo.device.OpenapiSetDeviceServicePropertyBo;
import cc.iotkit.openapi.dto.vo.*;
import cc.iotkit.openapi.service.OpenDeviceService;
import cn.dev33.satoken.annotation.SaCheckLogin;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Api(tags = {"openapi-设备"})
@Slf4j
@RestController
@RequestMapping("/openapi/device")
public class OpenDeviceController {

    @Autowired
    @Qualifier("deviceInfoDataCache")
    private IDeviceInfoData deviceInfoData;

    @Autowired
    private OpenDeviceService openDeviceService;
    @Autowired
    private IDeviceManagerService deviceServiceImpl;
    @Autowired
    private AlertService alertService;
    @Autowired
    DoorAccessRecordService doorAccessRecordService;

    @ApiOperation("查询单个设备详情")
    @PostMapping("/v1/detail")
    @SaCheckLogin
    public DeviceInfo getDetail(@RequestBody @Validated Request<OpenapiDeviceBo> bo) {
        return openDeviceService.getDetail(bo.getData());
    }

    @ApiOperation(value = "单个设备注册")
    @PostMapping("/v1/registerDevice")
    public OpenDeviceInfoVo createDevice(@RequestBody @Validated Request<OpenapiDeviceBo> bo) {
        return openDeviceService.addDevice(bo.getData());
    }

    @ApiOperation("单个设备删除")
    @PostMapping("/v1/deleteDevice")
    public boolean deleteDevice(@Validated @RequestBody Request<OpenapiDeviceBo> bo) {
        return openDeviceService.deleteDevice(bo.getData());
    }

    @ApiOperation(value = "设置设备的属性", notes = "设置设备的属性", httpMethod = "POST")
    @PostMapping("/v1/setDeviceProperty")
    public InvokeResult setProperty(@RequestBody @Validated Request<OpenapiSetDeviceServicePropertyBo> request) {
        return new InvokeResult(openDeviceService.setProperty(request.getData().getProductKey(), request.getData().getDeviceName(), request.getData().getArgs()));
    }

    @ApiOperation("查询指定设备的属性快照")
    @PostMapping("/v1/queryDevicePropertyStatus")
    public OpenDevicePropertyVo getDevicePropertyStatus(@RequestBody @Validated Request<OpenapiDeviceBo> bo) {
        return openDeviceService.getDevicePropertyStatus(bo.getData());
    }

    /**
     * 通过固定接口，查询设备的运行概况，通过输入参数可以获取全部接入设备的数量以及各分项（正常、离线、故障）的数量，也可以单独获取每个分项的数量
     *
     * @return
     */
    @ApiOperation("获取全部设备的状态统计")
    @GetMapping("/v1/queryStatusCount")
    @SaCheckLogin
    public OpenDeviceStatusCountVo queryStatusCount() {
        OpenDeviceStatusCountVo openDeviceStatusCountVo = new OpenDeviceStatusCountVo();
        DeviceInfo condition = new DeviceInfo();
        DeviceInfo.State state = new DeviceInfo.State();
        state.setOnline(true);
        condition.setState(state);
        openDeviceStatusCountVo.setOnlineTotal(deviceInfoData.findAllByCondition(condition).size());

        state.setOnline(false);
        condition.setState(state);
        openDeviceStatusCountVo.setOfflineTotal(deviceInfoData.findAllByCondition(condition).size());

        return openDeviceStatusCountVo;
    }

    /**
     * 通过固定接口，获取当前的温度、湿度、可燃气体、氧气浓度等数量的统计
     * 传设备号+属性名称 --获取某设备某属性当前数据
     * 传产品号+属性名称 --获取某产品下所有设备的某属性平均数据
     *
     * @return
     */
    @ApiOperation("环境监测统计")
    @PostMapping("/v1/querySurroundingsData")
    @SaCheckLogin
    public OpenSurroundingsVo querySurroundingsData(@RequestBody @Validated Request<OpenapiDevicePublicBo> bo) {
        OpenSurroundingsVo surroundingsVo = new OpenSurroundingsVo();
        PageRequest<DeviceQueryBo> pageRequest = new PageRequest<>();
        DeviceQueryBo deviceQueryBo = new DeviceQueryBo();
        pageRequest.setData(deviceQueryBo);
        pageRequest.getData().setKeyword(bo.getData().getDeviceName());
        pageRequest.getData().setProductKey(bo.getData().getProductKey());
        pageRequest.setPageSize(9999);
        pageRequest.setPageNum(1);
        //根据产品编码和设备DN查询设备列表（如果传了DN，正常只能查出来一个设备，DN唯一）
        Paging<DeviceInfoVo> deviceInfoVoPaging = deviceServiceImpl.getDevices(pageRequest);
        float temp = 0f;
        float humidity = 0f;
        float combustibleGas = 0f;
        float oxygen = 0f;
        if (deviceInfoVoPaging != null && deviceInfoVoPaging.getRows() != null && deviceInfoVoPaging.getRows().size() > 0) {
            List<DeviceInfoVo> deviceInfoVoList = deviceInfoVoPaging.getRows();
            //循环查询设备 对应的属性【humidity 湿度，temperature 温度，gasStrength1 探头1暂定可燃气体，gasStrength2 探头2暂定氧气】
            for (DeviceInfoVo deviceInfoVo : deviceInfoVoList) {
                Map<String, DevicePropertyCache> properties = deviceInfoData.getProperties(deviceInfoVo.getDeviceId());
                if (properties.get("temperature") != null) {
                    //累计温度
                    temp += Float.parseFloat(properties.get("temperature").getValue() + "");
                }
                if (properties.get("humidity") != null) {
                    //累计湿度
                    humidity += Float.parseFloat(properties.get("humidity").getValue() + "");
                }
                if (properties.get("gasStrength1") != null) {
                    //累计探头1气体浓度
                    combustibleGas += Float.parseFloat(properties.get("gasStrength1").getValue() + "");
                }
                if (properties.get("gasStrength2") != null) {
                    //累计探头2气体浓度
                    oxygen += Float.parseFloat(properties.get("gasStrength2").getValue() + "");
                }
            }
            temp = temp / deviceInfoVoList.size();
            humidity = humidity / deviceInfoVoList.size();
            combustibleGas = combustibleGas / deviceInfoVoList.size();
            oxygen = oxygen / deviceInfoVoList.size();
        }
        surroundingsVo.setTemp(temp);
        surroundingsVo.setHumidity(humidity);
        surroundingsVo.setCombustibleGas(combustibleGas);
        surroundingsVo.setOxygen(oxygen);
        return surroundingsVo;
    }

    @ApiOperation(value = "当前电能负荷", notes = "当前电能负荷", httpMethod = "POST")
    @SaCheckLogin
    @PostMapping("/v1/getElectricEnergy")
    public float getElectricEnergy(@Validated @RequestBody PageRequest<DeviceQueryBo> pageRequest) {
        Paging<DeviceInfoVo> deviceInfoVoPaging = deviceServiceImpl.getDevices(pageRequest);
        float electricEnergy = 0f;
        if (deviceInfoVoPaging != null && deviceInfoVoPaging.getRows() != null && deviceInfoVoPaging.getRows().size() > 0) {
            List<DeviceInfoVo> deviceInfoVoList = deviceInfoVoPaging.getRows();
            for (DeviceInfoVo deviceInfoVo : deviceInfoVoList) {
                Map<String, DevicePropertyCache> properties = deviceInfoData.getProperties(deviceInfoVo.getDeviceId());
                if (properties.get("electricEnergy") != null) {
                    //累计电能
                    electricEnergy += Float.parseFloat(properties.get("electricEnergy").getValue() + "");
                }
            }
        }
        return electricEnergy;
    }

    @ApiOperation(value = "设备开关状态监控统计", notes = "设备开关状态监控统计", httpMethod = "POST")
    @SaCheckLogin
    @PostMapping("/v1/getSwitchCount")
    public OpenSwitchCountVo getSwitchCount(@Validated @RequestBody PageRequest<DeviceQueryBo> pageRequest) {
        OpenSwitchCountVo openSwitchCountVo = new OpenSwitchCountVo();
        Paging<DeviceInfoVo> deviceInfoVoPaging = deviceServiceImpl.getDevices(pageRequest);
        int onCount = 0;
        int offCount = 0;
        int allCount = 0;
        if (deviceInfoVoPaging != null && deviceInfoVoPaging.getRows() != null && deviceInfoVoPaging.getRows().size() > 0) {
            List<DeviceInfoVo> deviceInfoVoList = deviceInfoVoPaging.getRows();
            for (DeviceInfoVo deviceInfoVo : deviceInfoVoList) {
                Map<String, DevicePropertyCache> properties = deviceInfoData.getProperties(deviceInfoVo.getDeviceId());
                if (properties.get("onOff") != null && "1".equals(properties.get("onOff").getValue() + "")) {
                    onCount += 1;
                } else {
                    offCount += 1;
                }
            }
            allCount = deviceInfoVoList.size();
        }
        openSwitchCountVo.setOnCount(onCount);
        openSwitchCountVo.setOffCount(offCount);
        openSwitchCountVo.setAllCount(allCount);
        return openSwitchCountVo;
    }

    @ApiOperation("查询告警消息分页")
    @SaCheckLogin
    @PostMapping("/v1/selectAlertRecordPage")
    public Paging<AlertRecord> selectAlertRecordPage(@RequestBody @Validated PageRequest<AlertRecord> request) {
        return alertService.selectAlertRecordPage(request);
    }

    @ApiOperation("设备查询：可根据设备名称、楼层、设备类型、状态类型（全部、正常、离线、故障）等对设备列表进行查询。设备列表具体显示内容包括：设备编号、设备具体名称（楼层、房间、设备名称）\n" +
            "地址（楼层、房间）")
    @SaCheckLogin
    @PostMapping("/v1/list")
    public List<DeviceInfoMiniVo> list(@RequestBody @Validated PageRequest<DeviceQueryBo> pageRequest) {
        List<DeviceInfoMiniVo> miniVoList = new ArrayList<>();
        pageRequest.setPageSize(9999);
        pageRequest.setPageNum(1);
        Paging<DeviceInfoVo> deviceInfoVoPaging = deviceServiceImpl.getDevices(pageRequest);
        if (deviceInfoVoPaging != null && deviceInfoVoPaging.getRows() != null && deviceInfoVoPaging.getRows().size() > 0) {
            List<DeviceInfoVo> deviceInfoVoList = deviceInfoVoPaging.getRows();
            DeviceInfoMiniVo miniVo = null;
            for (DeviceInfoVo deviceInfoVo : deviceInfoVoList) {
                miniVo = new DeviceInfoMiniVo();
                miniVo.setDeviceId(deviceInfoVo.getDeviceId());
                miniVo.setDeviceName(deviceInfoVo.getDeviceName());
                if (deviceInfoVo.getGroup() != null) {
                    miniVo.setRoom(deviceInfoVo.getGroup().getName());
                }
                miniVo.setFloor(deviceInfoVo.getFloor());
                miniVo.setProductKey(deviceInfoVo.getProductKey());
                miniVo.setProductName(deviceInfoVo.getProduct().getName());
                miniVoList.add(miniVo);
            }
        }
        return miniVoList;
    }

    @ApiOperation("该接口需要使用MQTT协议进行订阅，通过设置主题的方式获取数据" +
            "1、可根据产品分类获取该类别下所有设备的实时运行数据" +
            "2、可根据设备获取该设备的实时运行数据" +
            "数据包括：设备编号、设备名称、设备运行状态以及接入需要的其他运行参数数据")
    @SaCheckLogin
    @PostMapping("/v1/runningData")
    public List<DeviceInfoMiniVo> runningData(@RequestBody @Validated PageRequest<DeviceQueryBo> pageRequest) {
        List<DeviceInfoMiniVo> miniVoList = new ArrayList<>();
        pageRequest.setPageSize(9999);
        pageRequest.setPageNum(1);
        Paging<DeviceInfoVo> deviceInfoVoPaging = deviceServiceImpl.getDevices(pageRequest);
        if (deviceInfoVoPaging != null && deviceInfoVoPaging.getRows() != null && deviceInfoVoPaging.getRows().size() > 0) {
            List<DeviceInfoVo> deviceInfoVoList = deviceInfoVoPaging.getRows();
            DeviceInfoMiniVo miniVo = null;
            for (DeviceInfoVo deviceInfoVo : deviceInfoVoList) {
                Map<String, DevicePropertyCache> properties = deviceInfoData.getProperties(deviceInfoVo.getDeviceId());
                miniVo = new DeviceInfoMiniVo();
                miniVo.setProperty(properties);
                miniVo.setDeviceId(deviceInfoVo.getDeviceId());
                miniVo.setDeviceName(deviceInfoVo.getDeviceName());
                if (deviceInfoVo.getGroup() != null) {
                    miniVo.setRoom(deviceInfoVo.getGroup().getName());
                }
                miniVo.setFloor(deviceInfoVo.getFloor());
                miniVo.setProductKey(deviceInfoVo.getProductKey());
                miniVo.setProductName(deviceInfoVo.getProduct().getName());
                miniVo.setOnline(deviceInfoVo.getOnline());
                miniVoList.add(miniVo);
            }
        }
        return miniVoList;
    }

    /**
     * 温湿度查询的字段包括：设备名称、楼层、房间、温度、湿度、时间等
     *
     * @return
     */
    @ApiOperation("温湿度查询")
    @PostMapping("/v1/queryHumiture")
    @SaCheckLogin
    public OpenDeviceInfoProVo queryHumiture(@RequestBody @Validated Request<OpenapiDeviceBo> bo) {
        DeviceInfo deviceInfo = openDeviceService.getDetail(bo.getData());
        PageRequest<DeviceLogQueryBo> request = new PageRequest<>();
        DeviceLogQueryBo deviceLogQueryBo = new DeviceLogQueryBo();
        deviceLogQueryBo.setType("property");
        deviceLogQueryBo.setIdentifier("report");
        deviceLogQueryBo.setDeviceId(deviceInfo.getDeviceId());
        deviceLogQueryBo.setProductKey(deviceInfo.getProductKey());
        deviceLogQueryBo.setTimeStart(bo.getData().getTimeStart());
        deviceLogQueryBo.setTimeEnd(deviceLogQueryBo.getTimeEnd());
        request.setData(deviceLogQueryBo);
        Paging<ThingModelMessage> thingModelMessagePaging = deviceServiceImpl.logs(request);

        OpenDeviceInfoProVo openDeviceInfoProVo = new OpenDeviceInfoProVo();
        openDeviceInfoProVo.setGroup(deviceInfo.getGroup());
        openDeviceInfoProVo.setDeviceName(deviceInfo.getDeviceName());
        openDeviceInfoProVo.setDeviceId(deviceInfo.getDeviceId());
        openDeviceInfoProVo.setFloor(deviceInfo.getFloor());
        openDeviceInfoProVo.setModelMessages(thingModelMessagePaging.getRows());
        openDeviceInfoProVo.setProductKey(deviceInfo.getProductKey());
        return openDeviceInfoProVo;
    }

    @ApiOperation("安防监控统计:获取摄像头、门禁的具体数量，以及近24小时内的人员出入次数。")
    @SaCheckLogin
    @PostMapping("/v1/securityData")
    public OpenSecurityDataVo security(@RequestBody @Validated PageRequest<DoorAccessRecord> query) {
        OpenSecurityDataVo openSecurityDataVo = new OpenSecurityDataVo();
        PageRequest<DeviceQueryBo> pageRequest = new PageRequest<>();
        DeviceQueryBo deviceQueryBo = new DeviceQueryBo();
        //门禁key
        deviceQueryBo.setProductKey("FQeATzSQNmJDZkpn");
        pageRequest.setData(deviceQueryBo);
        pageRequest.setPageSize(9999);
        pageRequest.setPageNum(1);
        Paging<DeviceInfoVo> deviceInfoVoPaging = deviceServiceImpl.getDevices(pageRequest);
        openSecurityDataVo.setAccessControl(deviceInfoVoPaging.getRows().size());
        //摄像头
        deviceQueryBo.setProductKey("yEXMDrzpCGYs5MwX");
        pageRequest.setData(deviceQueryBo);
        deviceInfoVoPaging = deviceServiceImpl.getDevices(pageRequest);
        openSecurityDataVo.setCameraCount(deviceInfoVoPaging.getRows().size());
        //人员出入记录
        Paging<DoorAccessRecordVo> doorAccessRecordVoPaging = doorAccessRecordService.selectPageDoorAccessRecordList(query);

        openSecurityDataVo.setDoorAccessRecordVoList(doorAccessRecordVoPaging.getRows());
        return openSecurityDataVo;
    }

    @ApiOperation("获取当前能耗（单位kw）;24小时累计用电（单位kw·h）;以及近24小时内的分项用电情况（分项包括：空调、照明、FFU、实验区）")
    @SaCheckLogin
    @GetMapping("/v1/electricityDataDay")
    public OpenElectricityDataDayVo electricityDataDay() {
        OpenElectricityDataDayVo electricityDataVo = new OpenElectricityDataDayVo();
        electricityDataVo.setEnergyConsumption24H_ffu(111.12f);
        electricityDataVo.setEnergyConsumption24H_all(92381.12f);
        electricityDataVo.setEnergyConsumption24H_air(1213.2f);
        electricityDataVo.setEnergyConsumption24H_lighte(1293.1f);
        electricityDataVo.setEnergyConsumption24H_test(1293.3f);
        electricityDataVo.setEnergyConsumptionNow(23421.2f);
        return electricityDataVo;
    }
    @ApiOperation("按照楼层获取近30天内分项用电统计情况，分项包括：空调、FFU、照明、实验区、其他等")
    @SaCheckLogin
    @GetMapping("/v1/electricityDataMonth")
    public OpenElectricityDataMonthVo electricityDataMonth() {
        OpenElectricityDataMonthVo electricityDataVo = new OpenElectricityDataMonthVo();
        electricityDataVo.setEnergyConsumption30D_ffu(111.12f);
        electricityDataVo.setEnergyConsumption30D_all(92381.12f);
        electricityDataVo.setEnergyConsumption30D_air(1213.2f);
        electricityDataVo.setEnergyConsumption30D_lighte(1293.1f);
        electricityDataVo.setEnergyConsumption30D_test(1293.3f);
        electricityDataVo.setEnergyConsumptionNow(23421.2f);
        return electricityDataVo;
    }

    @ApiOperation("获取近24小时内的报警数量以及维保提醒数量，其中报警数量包括：设备故障和设备离线")
    @SaCheckLogin
    @GetMapping("/v1/alarmData")
    public Map alarmData() {
        Map map = new HashMap();
        map.put("breakdownCount",4);
        map.put("offLienCount",12);
        return map;
    }

    @ApiOperation("按照楼层获取今日能耗峰值时间及峰值负荷（单位:kw）")
    @SaCheckLogin
    @GetMapping("/v1/peakElectricityData")
    public Map peakElectricityData() {
        Map map = new HashMap();
        map.put("peakTime1",1714399178656l);
        map.put("peakLoadData1",456743);
        map.put("peakTime2",1714399178656l);
        map.put("peakLoadData2",3456765);
        return map;
    }

    @ApiOperation("按照楼层获取今日累计用电（单位:kw·h）以及折合的电价（单位：元）")
    @SaCheckLogin
    @GetMapping("/v1/todayElectricityData")
    public Map todayElectricityData() {
        Map map = new HashMap();
        map.put("total1",121);
        map.put("totalCost1",312);
        map.put("total2",12);
        map.put("totalCost2",234);
        return map;
    }

    @ApiOperation("按照楼层获取今日用电分区统计，按照楼层和房间来划分，要显示整栋楼的数据时，展示的就是每个楼层的用电情况，" +
            "当点击楼层后，要显示的就是本楼层内个房间区域的用电情况。")
    @SaCheckLogin
    @GetMapping("/v1/todayRoomElectricityData")
    public OpenRoomElectricityDataVo todayRoomElectricityData() {
        OpenRoomElectricityDataVo roomElectricityDataVo = new OpenRoomElectricityDataVo();
        roomElectricityDataVo.setTotalElectricity1(12324f);
        roomElectricityDataVo.setTotalElectricity2(982f);
        List<OpenRoomElectricityDataVo.RoomElectricity> roomElectricityList1 = new ArrayList<>();
        roomElectricityList1.add(new OpenRoomElectricityDataVo.RoomElectricity("一层101",121f));
        roomElectricityList1.add(new OpenRoomElectricityDataVo.RoomElectricity("一层102",421f));
        roomElectricityDataVo.setRoomElectricityList1(roomElectricityList1);

        List<OpenRoomElectricityDataVo.RoomElectricity> roomElectricityList2 = new ArrayList<>();
        roomElectricityList2.add(new OpenRoomElectricityDataVo.RoomElectricity("二层201",121f));
        roomElectricityList2.add(new OpenRoomElectricityDataVo.RoomElectricity("二层202",421f));
        roomElectricityDataVo.setRoomElectricityList2(roomElectricityList2);

        return roomElectricityDataVo;
    }

    @ApiOperation("按照楼层获取今日用电的排名情况，排名按照由高到低降序排列，返回的参数包括序号、区域名称、用电量（单位：kw·h），历史均值（单位：kw·h）")
    @SaCheckLogin
    @GetMapping("/v1/todayElectricityDataSort")
    public List<Map> todayElectricityDataSort() {
        List<Map> mapList = new ArrayList<>();
        Map map = new HashMap();
        map.put("sortNo",1);
        map.put("area",312);
        map.put("totalE",12);
        map.put("averageE",234);
        mapList.add(map);
        return mapList;
    }
}